#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

#define MAX 100
#define THREADNUM 4

static int num = 0; // the num that give to thread to compute
static pthread_mutex_t mut_num = PTHREAD_MUTEX_INITIALIZER;

void *thread_func(void *arg)
{
  int i;
  while (1) {
    pthread_mutex_lock(&mut_num);
    if (num == -1) {
      pthread_mutex_unlock(&mut_num);
      pthread_exit(arg);
    } else if (num != 0) {
      i = num;
      num = 0;
      pthread_mutex_unlock(&mut_num);
      int flag = 1;
      for (int j = 2; j <= i / 2; j++) {
        if (i % j == 0) {
          flag = 0;
          break;
        }
      }

      if (flag) {
        printf("thread%d: %d\n", *(int*)arg, i);
      }
    } else {
      pthread_mutex_unlock(&mut_num);
    }
  }

  fprintf(stderr, "error\n"); 
  exit(1);
}

int main()
{
  pthread_t thread_ids[THREADNUM] = {0};
  int err;
  void *retvalue;
  for (int i = 0; i < THREADNUM; i++) {
    int *ip = (int *)malloc(sizeof(int));
    *ip = i; 
    err = pthread_create(thread_ids + i, NULL, thread_func, ip);
    if (err) {
      fprintf(stderr, "pthread_create");
      exit(1);
    }
  }

  // assign compute task to thread
  for (int i = 2; i < MAX; i++) {
    while (1) {
      pthread_mutex_lock(&mut_num);
      if (num == 0) {
        num = i;
	pthread_mutex_unlock(&mut_num);
	break;
      }
      pthread_mutex_unlock(&mut_num);
      sched_yield(); // yield cpu
    }
  }

  // set num to -1, means all work has done
  while (1) {
    pthread_mutex_lock(&mut_num);
    if (num == 0) {
      num = -1;
      pthread_mutex_unlock(&mut_num);
      break;
    }
    pthread_mutex_unlock(&mut_num);
    sched_yield(); // yield cpu
  }

  for (int i = 0; i < THREADNUM; i++) {
    if (thread_ids[i] != 0) {
      pthread_join(thread_ids[i], &retvalue);
      free(retvalue);
    }
  }

  pthread_mutex_destroy(&mut_num);
  exit(0);
}
